package SC12Project.Milestone1.Payment;

import java.io.File;
import java.io.FileNotFoundException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

/**
 * Service provider for a Payment system.
 * 
 * @author Stefanos
 */
public class PaymentProvider
    implements PaymentWS
{

    private BanKInfo bankInfo;

    private File f;

    /*
     * public static void main(String... args){ PaymentProvider pp = new PaymentProvider();
     * System.out.println("stef has " + pp.queryAccount("stef")); System.out.println("vasia has " +
     * pp.queryAccount("vasia")); try { if (pp.transfer("stef","vasia",10)) { System.out.println("stef has " +
     * pp.queryAccount("stef")); System.out.println("vasia has " + pp.queryAccount("vasia")); } } catch
     * (TransactionException e) { e.printStackTrace(); } }
     */

    public PaymentProvider()
    {
        parseAndInit( "../datasource/ds_2_3.xml" );
    }

    void parseAndInit( String path )
    {
        this.f = new File( path );
        /*
         * try { JAXBContext context = JAXBContext.newInstance(BanKInfo.class); this.u = context.createUnmarshaller();
         * this.m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
         * this.bankInfo = (BanKInfo) u.unmarshal(f); bankInfo.getAccount().get(0).setAmount(100); this.m =
         * context.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
         * m.marshal(bankInfo,f); } catch (JAXBException e) { e.printStackTrace(); }
         */

        try
        {
            ClassLoader cl = SC12Project.Milestone1.Payment.ObjectFactory.class.getClassLoader();
            String packageName = BanKInfo.class.getPackage().getName();
            JAXBContext jc = JAXBContext.newInstance( packageName, cl );
            Unmarshaller u = jc.createUnmarshaller();
            @SuppressWarnings( "unchecked" )
            JAXBElement<BanKInfo> root = (JAXBElement<BanKInfo>) u.unmarshal( f );
            bankInfo = root.getValue();

        }
        catch ( JAXBException e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    /**
     * Query the balance of an account
     * 
     * @param accountID
     * @return balance of the account
     */
    @Override
    public int queryAccount( String accountID )
    {
        int balance = 0;
        int i = 0;
        for ( i = 0; i < this.bankInfo.getAccount().size(); i++ )
        {
            if ( this.bankInfo.getAccount().get( i ).getAccountID().equals( accountID ) )
            {
                balance = this.bankInfo.getAccount().get( i ).getAmount();
            }
        }
        return balance;
    }

    /**
     * Transfer money from account1 to account2
     * 
     * @param accountID1 payee
     * @param accountID2 benefiter
     * @param amount the amount of money transfered from account1 to account2
     * @return true if the transaction is successful; otherwise false;
     */
    /*
     * (non-Javadoc)
     * @see SC12Project.Milestone1.Payment.PaymentWS#transfer(java.lang.String, java.lang.String, int)
     */
    @Override
    public boolean transfer( String accountID1, String accountID2, int amount )
        throws TransactionException
    {
        if ( amount > 0 )
        {
            int i = 0;
            int j = 0;
            int newBalance = 0;
            boolean transferValid;
            boolean account1Exists = false;
            boolean account2Exists = false;
            for ( i = 0; i < this.bankInfo.getAccount().size(); i++ )
            { // search for account ID1
                if ( this.bankInfo.getAccount().get( i ).getAccountID().equals( accountID1 ) )
                { // if account ID1 is found
                    account1Exists = true;
                    for ( j = 0; j < this.bankInfo.getAccount().size(); j++ )
                    { // search for account ID2
                        if ( ( this.bankInfo.getAccount().get( j ).getAccountID().equals( accountID2 ) ) && i != j )
                        { // if account ID2 is found
                            account2Exists = true;
                            if ( ( ( this.bankInfo.getAccount().get( i ).getAmount() ) - amount ) >= 0 )
                            { // Check if the payee can send the money

                                /* for the payee */
                                newBalance = this.bankInfo.getAccount().get( i ).getAmount() - amount;
                                this.bankInfo.getAccount().get( i ).setAmount( newBalance );
                                /* for the benefiter */
                                newBalance = this.bankInfo.getAccount().get( j ).getAmount() + amount;
                                this.bankInfo.getAccount().get( j ).setAmount( newBalance );
                                /* update xml file */
                                try
                                {
                                    this.marshalIntoXMLFile();
                                }
                                catch ( JAXBException e )
                                {
                                    e.printStackTrace();
                                }
                                catch ( FileNotFoundException e )
                                {
                                    e.printStackTrace();
                                }
                                transferValid = true;
                                return transferValid;
                            }
                            else
                            {
                                throw new TransactionException( "Payee's balance is not enough for the transaction" );
                            }
                        }
                    }
                }
            }
            /*
             * transferValid=false; return transferValid;
             */
            if ( !account1Exists )
            {
                throw new TransactionException( "ID account 1 does not exist" );
            }
            if ( !account2Exists )
            {
                throw new TransactionException( "ID account 2 does not exist" );
            }
        }
        else
        {
            throw new TransactionException( "You cannot transfer negative or zero amount of money" );
        }
        return false;
    }

    void marshalIntoXMLFile()
        throws JAXBException, FileNotFoundException
    {
        ClassLoader cl = SC12Project.Milestone1.Payment.ObjectFactory.class.getClassLoader();
        String packageName = BanKInfo.class.getPackage().getName();
        JAXBContext jc = JAXBContext.newInstance( packageName, cl );
        Marshaller m = jc.createMarshaller();
        m.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
        ObjectFactory obf = new ObjectFactory();
        JAXBElement<BanKInfo> output = obf.createBank( bankInfo );
        m.marshal( output, f );
    }

}
